#include "UnloadCommand.h"


UnloadCommand::UnloadCommand(SQLSystem* sql): Command(sql)
{
}


UnloadCommand::~UnloadCommand()
{
}

int UnloadCommand::execute(const string &str)
{
	vector<string> columnsToSave;
	vector<Row *> rowsToSave;
	bool allColumn=false;
	Table* table;
	SQLSystem* system= getSystem();
	string fileName;
	string delimiter;
	typedef tokenizer<char_separator<char> > token;
	char_separator<char> sep(" ","',",drop_empty_tokens);
	token tok(str, sep);
	token::iterator tok_iter= tok.begin();
	++tok_iter;
	if(tok_iter == tok.end() || helper->toUpperString(*tok_iter) != "TO")
		return false;
	++tok_iter;
	//filename to save the table
	if(*tok_iter != "'")
		return false;
	++tok_iter;
	while(*tok_iter != "'")
	{
		fileName += *tok_iter;
		++tok_iter;
	}
	++tok_iter;
	if(helper->toUpperString(*tok_iter) !="DELIMITER")
		return false;
	++tok_iter;
	//delimiter defined
	if(*tok_iter != "'")
		return false;
	++tok_iter;
	while(*tok_iter != "'")
	{
		delimiter += *tok_iter;
		++tok_iter;
	}
	++tok_iter;
	//select clause to select rows from a table to save to the record
	if(helper->toUpperString(*tok_iter) != "SELECT")
		return false;
	++tok_iter;
	if(*tok_iter == "*")
	{
		++tok_iter;
		allColumn= true;
	}
	else
	{
		while(helper->toUpperString(*tok_iter)!="FROM")
		{
			columnsToSave.push_back(*tok_iter);
			++tok_iter;
			if(*tok_iter == ",")
			{
				++tok_iter;
				continue;
			}
		}
		
	}

	++tok_iter;
	table= system->getTableByName(*tok_iter);
	if(!table)
	{
		cout << "Table not found\n";
		return false;
	}
	if(allColumn)
		columnsToSave= table->getColumns();
	
	//WHERE part
	++tok_iter;
	//if token ends here, no where part
	//print the whole table
	if(tok_iter == tok.end())
	{
		vector<int> types= table->getTypes();
		rowsToSave= table->getRows();
		saveToFile(fileName, delimiter, columnsToSave, rowsToSave, table);
		return true;
	}
	if(helper->toUpperString(*tok_iter) != "WHERE")
	{
		cout << "Missing WHERE statement\n";
		return false;
	}
	++tok_iter;
	string s;

	//after this loop s will contains the where part of the command
	//without any spaces
	while(tok_iter!=tok.end())
	{
		s +=*tok_iter;
		++tok_iter;
	}
	WherePart whereClause;
	whereClause.selectRows(s, table);
	rowsToSave= whereClause.getSelectedRows();
	saveToFile(fileName, delimiter, columnsToSave, rowsToSave, table);
	return true;
	
}

void UnloadCommand::saveToFile(const string &file, const string &delimiter, vector<string> columnsToSave, vector<Row *> rowsToSave, Table* table)
{
	ofstream outStream;
	outStream.open(file.c_str());
	if(outStream.fail())
	{
		cout << "Error opening the file\n";
		return;
	}
	//save the columns to the file
	vector<int> indexOfColumns;
	for(unsigned int i=0;i<columnsToSave.size();i++)
	{
		outStream << columnsToSave[i];
		if(i!=(columnsToSave.size()-1))
			outStream << delimiter;
		int index= table->getColumnIndex(columnsToSave[i]);
		if(index != -1)
			indexOfColumns.push_back(index);
	}
	outStream << endl;	//end of column line
	//save the types to the file
	vector<int> types= table->getTypes();
	for(unsigned int i=0;i<indexOfColumns.size();i++)
	{
		outStream << types[indexOfColumns[i]];
		if(i!=(indexOfColumns.size()-1))
			outStream << delimiter;
	}
	outStream << "\n";
	for(unsigned int j=0;j<rowsToSave.size();j++)
	{
		for(unsigned i=0;i<indexOfColumns.size();i++)
		{
			vector<Cell *> cells= rowsToSave[j]->getCells();
			Cell* cell= cells[indexOfColumns[i]];
			if(types[indexOfColumns[i]] == VARCHAR)
			{
				VarcharCell* vCell= dynamic_cast<VarcharCell *>(cell);								
				if(!vCell)
				{
					NullCell* nCell= dynamic_cast<NullCell *>(cell);
					if(!nCell)
					{
						cout << "NUll pointer" <<endl;
						return;
					}
					outStream << "NULL";
					if(i!=(indexOfColumns.size()-1))
						outStream << delimiter;
					continue;	//missing this cause troule 'cause you continue to extract data from a null cell->>exception
				}
				else
				{
					string data= vCell->getData();
					outStream << data;
					if(i!=(indexOfColumns.size()-1))
						outStream << delimiter;
				}


			}
			else if(types[indexOfColumns[i]] == INT)
			{
				IntCell* iCell= dynamic_cast<IntCell *>(cell);
				if(!iCell)
				{
					NullCell* nCell= dynamic_cast<NullCell *>(cell);
					if(!nCell)
					{
						cout << "NUll pointer" <<endl;
						return;
					}
					outStream << "NULL";
					if(i!=(indexOfColumns.size()-1))
						outStream << delimiter;
					continue;	//missing this cause troule 'cause you continue to extract data from a null cell->>exception
				}
				int data= iCell->getData();
				outStream << data;
				if(i!=(indexOfColumns.size()-1))
					outStream << delimiter;
			}
			
		}
		outStream << "\n";
	}
	outStream << "\n";
	outStream.close();
	cout << "DATA SAVED TO FILE\n";
}
